using System;
using System.Drawing;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

using Pegasus.Collections.Generic;
using Pegasus.Diagnostics;

namespace Pegasus.Windows.Forms
{
	/// <summary>
	/// Derives from the Form class and add functionality to save the last position of the window.  The data
	/// is stored on a per-user, in the user's system application data.  Also privates the FormSetting property
	/// for saving data to the same file.
	/// </summary>
	public class FormEx : Form
	{
		// Local Instance Values
		private DictionaryApplicationData<string, object> m_appData;
		private DictionaryUserData<string, object> m_userData;

		private Rectangle m_windowBounds;

		// Local Const Values
		private const string SETTINGS_BOUNDS = "Window.Bounds";
		private const string SETTINGS_STATE = "Window.State";

        /// <summary>
        /// Initializes a new instance of the <see cref="FormEx"/> class.
        /// </summary>
        public FormEx()
        {
            // Read in the user dictionary
            m_appData = new DictionaryApplicationData<string, object>( "DefaultDesigner" );
            m_userData = new DictionaryUserData<string, object>( "DefaultDesigner" );
        }

		/// <summary>
		/// Initializes a new instance of the <see cref="FormEx"/> class.
		/// </summary>
		/// <param name="storeName">Name of the store to save the data in.</param>
		public FormEx( string storeName ) 
		{
			// Check Parameters
			ParamCode.AssertNotEmpty( storeName, "storeName" );

			// Read in the user dictionary
			m_appData = new DictionaryApplicationData<string, object>( storeName );
			m_userData = new DictionaryUserData<string, object>( storeName );
		}

		/// <summary>
		/// Gets the application data.
		/// </summary>
		/// <value>The application data.</value>
		[Browsable( false )]
		public Dictionary<string, object> ApplicationData
		{
			get
			{
				return m_appData;
			}
		}

		/// <summary>
		/// Gets the user data.
		/// </summary>
		/// <value>The user data.</value>
		[Browsable( false )]
		public Dictionary<string, object> UserData
		{
			get
			{
				return m_userData;
			}
		}

		/// <summary>
		/// Raises the <see cref="E:Load"/> event.
		/// </summary>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		protected override void OnLoad( EventArgs args )
		{
			base.OnLoad( args );
			LoadWindowSettings();
		}

		/// <summary>
		/// Raises the <see cref="E:Closed"/> event.
		/// </summary>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		protected override void OnClosed( EventArgs args )
		{
			base.OnClosed( args );
			
			SaveWindowSettings();

			m_appData.Save();
			m_userData.Save();
		}
		/// <summary>
		/// Raises the <see cref="E:Resize"/> event.
		/// </summary>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		protected override void OnResize( EventArgs args )
		{
			base.OnResize( args );

			// Save the new bounds only if we are in normal state
			if( WindowState == FormWindowState.Normal )
			{
				m_windowBounds = Bounds;
			}
		}

		/// <summary>
		/// Raises the <see cref="E:LocationChanged"/> event.
		/// </summary>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		protected override void OnLocationChanged( EventArgs args )
		{
			base.OnLocationChanged( args );

			// Save the new bounds only if we are in normal state
			if( WindowState == FormWindowState.Normal )
			{
				m_windowBounds = Bounds;
			}
		}

		/// <summary>
		/// Saves the applciation data.
		/// </summary>
		protected void SaveApplciationData()
		{
			m_appData.Save();
		}

		/// <summary>
		/// Saves the user data.
		/// </summary>
		protected void SaveUserData()
		{
			m_userData.Save();
		}

		/// <summary>
		/// Saves the window settings.
		/// </summary>
		private void SaveWindowSettings()
		{
			// Save the bound/position of the window.
			m_userData[ SETTINGS_BOUNDS ] = m_windowBounds;

			// Save the windows state
			m_userData[ SETTINGS_STATE ] = WindowState;
		}

		/// <summary>
		/// Loads the window settings.
		/// </summary>
		private void LoadWindowSettings()
		{
			if( m_userData.ContainsKey( SETTINGS_BOUNDS ) )
			{
				Rectangle formBounds = (Rectangle) m_userData[ SETTINGS_BOUNDS ];
				Rectangle desktopBounds = Desktop.Bounds;
				
				// If the window was saved off the current desktop then center the window
				// onto the primary display
				if( !desktopBounds.IntersectsWith( formBounds ) )
				{
					Rectangle primaryScreenBounds = Desktop.PrimaryDisplay.Bounds;
					if( formBounds.Width > primaryScreenBounds.Width )
					{
						formBounds.Width = primaryScreenBounds.Width;
					}

					if( formBounds.Height > primaryScreenBounds.Height )
					{
						formBounds.Height = primaryScreenBounds.Height;
					}

					// Center the form on the desktop
					int left = primaryScreenBounds.X + ( ( primaryScreenBounds.Width / 2 ) - ( formBounds.Width / 2 ) );
					int top = primaryScreenBounds.Y + ( ( primaryScreenBounds.Height / 2 ) - ( formBounds.Height / 2 ) );
					
					formBounds = new Rectangle( top, left, formBounds.Width, formBounds.Height );
				}

				// Move the window and save the bounds
				m_windowBounds = Bounds = formBounds;
			}

			if( m_userData.ContainsKey( SETTINGS_STATE ) )
			{
				// If the app was closed in a min state then just restore it to a normal state.
				FormWindowState state = (FormWindowState) m_userData[ SETTINGS_STATE ];
				if( state == FormWindowState.Minimized )
				{
					state = FormWindowState.Normal;
				}

				// Set the window state
				WindowState = state;
			}
		}
	}
}
